跳到主要内容

Python 线程相关

Python 提供了多线程编程的支持,可以通过 threading 模块来创建和管理线程。多线程允许你同时执行多个线程,每个线程都有自己的执行流程,但共享进程的内存空间。这使得多线程适用于需要并行执行任务的情况,例如 I/O 密集型操作或任务分发。

以下是一个简单的 Python 多线程示例以及一些用例:

创建和启动线程

import threading

def print_numbers():
for i in range(1, 6):
print(f"Number {i}")

def print_letters():
for letter in 'abcde':
print(f"Letter {letter}")

thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_letters)

thread1.start() # 启动线程1
thread2.start() # 启动线程2

thread1.join() # 等待线程1结束
thread2.join() # 等待线程2结束

这个示例创建了两个线程,分别打印数字和字母。threading.Thread 用于创建线程对象,target 参数指定要执行的函数。通过 start() 方法启动线程,并使用 join() 方法等待线程结束。

线程池

from concurrent.futures import ThreadPoolExecutor

def square(number):
return number ** 2

with ThreadPoolExecutor(max_workers=2) as executor:
results = executor.map(square, [1, 2, 3, 4, 5])

print(list(results))

concurrent.futures.ThreadPoolExecutor 允许你创建线程池,从而更好地管理和重复使用线程。在上述示例中,我们使用线程池来并行计算一组数字的平方。

定时器线程

import threading
import time

def print_message(message):
print(f"Message: {message}")

timer_thread = threading.Timer(5, print_message, args=("Hello, Timer!",))
timer_thread.start()

threading.Timer 允许你创建一个定时器线程,该线程在指定的时间后执行指定的函数。在上述示例中,我们创建了一个5秒后执行的定时器线程。

Python的多线程机制适用于许多并行编程场景,但需要注意的是,由于全局解释器锁(GIL)的存在,Python中的多线程在处理CPU密集型任务时可能无法充分发挥多核处理器的性能。因此,对于CPU密集型任务,更常见的做法是使用多进程。

线程睡眠

注意:单位是秒

#!/usr/bin/python
import time

print "Start : %s" % time.ctime()
time.sleep( 5 )
print "End : %s" % time.ctime()

所以可以搭配随机数使用

import random
import time

# random() 方法返回随机生成的一个实数,它在[0,1)范围内。
random.random()

max_time = 5.0
min_time = 1.3
time.sleep((random.random() * max_time) + min_time)

线程合并(join方法)

在线程编程中,线程合并(join)是一种等待一个线程完成其执行的方式,然后才继续执行其他线程或主线程。join 方法是用于线程合并的常见方法,它可以让一个线程等待另一个线程执行完毕。

在Python中,线程对象的 join 方法用于等待指定线程执行完毕。当调用 join 方法时,当前线程将被阻塞,直到被调用的线程(即被合并的线程)执行完成。下面是一个示例:

import threading

def worker():
print("Worker thread is running")

# 创建线程
thread = threading.Thread(target=worker)

# 启动线程
thread.start()

# 等待线程执行完毕
thread.join()

print("Main thread continues")

在这个示例中,我们创建了一个名为 worker 的线程,并使用 start 方法启动它。然后,在主线程中使用 join 方法等待 worker 线程执行完毕。只有在 worker 线程执行完成后,主线程才会继续执行。

join 方法还可以接受一个可选的超时参数,以指定最长等待时间。例如,可以使用 thread.join(timeout) 来等待线程的完成,但最多等待 timeout 秒,超时后继续执行主线程。

线程合并在协调和控制线程执行顺序以及确保线程间的同步上非常有用。它可以用于等待子线程完成计算、数据的准备或其他任务,然后在主线程中继续执行后续操作。这对于需要多线程协同工作的情况非常重要,以确保线程之间的正确协调和数据一致性。

Python 实现 WaitGroup

要等待全部线程完成后才继续执行主线程,可以使用一些方法来协调线程的执行。其中最常见的方法是使用 threading 模块中的 threading.Thread.join() 方法来等待每个线程的完成。以下是一个示例,演示如何等待所有线程完成后继续执行:

import threading

def worker(thread_id):
print(f"Worker {thread_id} is running")

# 创建线程列表
threads = []

# 创建并启动多个线程
for i in range(5):
thread = threading.Thread(target=worker, args=(i,))
thread.start()
threads.append(thread)

# 等待所有线程完成
for thread in threads:
thread.join()

print("All threads have finished. Main thread continues.")

在这个示例中,我们创建了一个包含多个线程的列表 threads,并将每个线程的实例添加到列表中。然后,我们使用循环迭代所有线程,并使用 join() 方法等待每个线程的完成。只有在所有线程都完成后,主线程才会继续执行。

另一种更高级的方法是使用 concurrent.futures 模块中的 ThreadPoolExecutorProcessPoolExecutor 来管理线程池或进程池,并使用 executor.map() 来执行任务。这种方式更加简洁,并且可以方便地等待所有任务完成。以下是一个使用 ThreadPoolExecutor 的示例:

from concurrent.futures import ThreadPoolExecutor

def worker(thread_id):
print(f"Worker {thread_id} is running")

# 创建线程池
with ThreadPoolExecutor(max_workers=5) as executor:
# 提交任务并等待所有任务完成
futures = [executor.submit(worker, i) for i in range(5)]

# 所有任务完成后,继续执行主线程
print("All threads have finished. Main thread continues.")

无论使用哪种方式,等待全部线程完成后才继续执行是一种常见的多线程编程模式,它确保了线程之间的协调和同步。这对于需要多线程协同工作的任务非常有用,以确保线程之间的正确协调和数据一致性。

Python 的互斥锁

Python 中的互斥锁(Mutex)是一种用于多线程编程的同步机制,它用于保护临界区(Critical Section)的访问,以确保在任何给定时刻只有一个线程能够访问共享资源。互斥锁是线程安全的方式,可以防止多个线程同时访问或修改共享资源,从而避免竞争条件(Race Condition)和数据不一致性问题。

Python 中的互斥锁通过 threading 模块提供。下面是使用互斥锁的基本示例:

import threading

# 创建互斥锁对象
mutex = threading.Lock()

shared_resource = 0

def increment_shared_resource():
global shared_resource
# 获取互斥锁
mutex.acquire()
try:
shared_resource += 1
finally:
# 释放互斥锁
mutex.release()

# 创建多个线程来访问共享资源
threads = []
for _ in range(5):
thread = threading.Thread(target=increment_shared_resource)
threads.append(thread)
thread.start()

# 等待所有线程完成
for thread in threads:
thread.join()

print(f"Final value of shared_resource: {shared_resource}")

在这个示例中,我们首先创建了一个互斥锁对象 mutex。然后,我们定义了一个函数 increment_shared_resource,它在访问共享资源之前获取互斥锁,并在完成后释放互斥锁。

接着,我们创建了多个线程,每个线程都会调用 increment_shared_resource 函数来增加共享资源的值。由于我们使用了互斥锁,多个线程不会同时访问 shared_resource,从而避免了竞争条件。

最后,我们等待所有线程完成,然后打印最终的共享资源值。

互斥锁是一种常见的线程同步工具,用于确保线程安全的访问共享资源。然而,要小心使用互斥锁,因为它可能导致线程阻塞或死锁的情况。因此,在编写多线程代码时,要特别注意互斥锁的获取和释放,以避免潜在的问题。

共享数据

import threading

counter = 0
lock = threading.Lock()

def increment_counter():
global counter
with lock:
counter += 1

def decrement_counter():
global counter
with lock:
counter -= 1

thread1 = threading.Thread(target=increment_counter)
thread2 = threading.Thread(target=decrement_counter)

thread1.start()
thread2.start()

thread1.join()
thread2.join()

print(f"Counter: {counter}")

在多线程环境中,共享数据需要使用锁来防止竞争条件。上述示例使用 threading.Lock 来确保对 counter 变量的安全访问。